﻿using System;
using c = NHibernate.Cfg;
using NHibernate;
using NHibernate.Criterion;

namespace OrmSmackdown.NHibernate
{
    public class Aggregate : IAggregate
    {
        ISessionFactory _sessionFactory;
        ISession _session;

        /// <summary>
        /// Initializes a new instance of the GoodAggregate class.
        /// </summary>
        public Aggregate()
        {
            c.Configuration _configuration = new c.Configuration();
            _configuration.AddAssembly("OrmSmackdown");
            _sessionFactory = _configuration.BuildSessionFactory();
            _session = _sessionFactory.OpenSession();
        }

        public void InsertRecordsApproachOne(int recordsToInsert)
        {
            using (var transaction = _session.BeginTransaction())
            {
                for (var idx = 0; idx < recordsToInsert; ++idx)
                    _session.Save(new Performance() { MilliSeconds = idx, Action = Constants.STR_AggregateCount, OrmName = "NHibernate" });

                transaction.Commit();
            }
        }

        public void InsertRecordsApproachTwo(int recordsToInsert)
        {
            for (var idx = 0; idx < recordsToInsert; ++idx)
                _session.Save(new Performance() { MilliSeconds = idx, Action = Constants.STR_AggregateCount, OrmName = "NHibernate" });

            _session.Flush();
        }

        public int GetCountApproachOne()
        {
            var query = _session
                .CreateCriteria(typeof(Performance))
                .Add(Expression.Eq("Action", Constants.STR_AggregateCount))
                .SetProjection(Projections.ProjectionList().Add(Projections.Count("PerformanceId")));

            return query.UniqueResult<Int32>();
        }

        public int GetCountApproachTwo()
        {
            var result = _session
                .CreateCriteria(typeof(Performance))
                .Add(Expression.Eq("Action", Constants.STR_AggregateCount))
                .SetProjection(Projections.ProjectionList()
                    .Add(Projections.Property("PerformanceId"), "PerformanceId"))
                    .List().Count;

            return result;
        }


        public int GetAverageApproachOne()
        {
            var query = _session.CreateCriteria(typeof(Performance))
                .Add(Expression.Eq("Action", Constants.STR_AggregateCount))
                .SetProjection(Projections.ProjectionList().Add(Projections.Avg("MilliSeconds")));

            return Convert.ToInt32(query.UniqueResult());
        }

        public int GetAverageApproachTwo()
        {
            var query = _session.CreateCriteria(typeof(Performance))
                         .Add(Expression.Eq("Action", Constants.STR_AggregateCount))
                         .SetProjection(Projections.ProjectionList().Add(Projections.Avg("MilliSeconds")));

            return Convert.ToInt32(query.UniqueResult());
        }

        public void DeleteRecordsApproachOne()
        {
            AdoNet.Aggregate.ClearAggregateCounts();
        }

        public void DeleteRecordsApproachTwo()
        {
            AdoNet.Aggregate.ClearAggregateCounts();
        }

        public void Dispose()
        {
            _session.Dispose();
            _sessionFactory.Dispose();
        }
    }
}
